
#pragma once
#include "Common/Definitions.h"

#include "Common/Math.h"
#include "ParameterType.h"

using namespace System::Collections::Generic;

namespace ttg_internal
{
	namespace utils
	{
		///<summary>
		/// Contains additional information about type and provides verification routines.
		///</summary>
		public ref class ParameterInfo abstract
		{
			private:
				ParameterType _type;
			protected:
				ParameterInfo(ParameterType type)
				{ _type = type; }
			internal:
				///<summary>
				/// Tries to get type by its serialization.
				/// Never throws exceptions.
				///</summary>
				static ParameterType determineType(System::String ^type);
			public:
				///<summary>
				/// Returns base type of parameter.
				///</summary>
				property ParameterType Type
				{
					ParameterType get()
					{ return _type; }
				}
				///<summary>
				/// Returns true, if value can be assigned to parameter-owner.
				///</summary>
				virtual bool CanBeAssigned(System::String ^value) = 0;
		};
		///<summary>
		/// Version for "Void" (will be used instead of exception throwing).
		///</summary>
		public ref class ParameterInfo_Void :public ParameterInfo
		{
			internal:
				///<summary>
				/// Creates info for type "ParameterType::Void".
				///</summary>
				ParameterInfo_Void(System::String ^type)
					:ParameterInfo(ParameterType::Void)
				{ /*nothing*/ }
			public:
				///<summary>
				/// Always returns false.
				///</summary>
				virtual bool CanBeAssigned(System::String ^value) override
				{ return false; }
		};
		///<summary>
		/// Version for "Bool".
		///</summary>
		public ref class ParameterInfo_Bool :public ParameterInfo
		{
			internal:
				///<summary>
				/// Creates info for type "ParameterType::Bool".
				///</summary>
				ParameterInfo_Bool(System::String ^type)
					:ParameterInfo(ParameterType::Bool)
				{ /*nothing*/ }
			public:
				virtual bool CanBeAssigned(System::String ^value) override;
		};
		///<summary>
		/// Version for "String".
		///</summary>
		public ref class ParameterInfo_String :public ParameterInfo
		{
			internal:
				///<summary>
				/// Creates info for type "ParameterType::String".
				///</summary>
				ParameterInfo_String(System::String ^type)
					:ParameterInfo(ParameterType::String)
				{ /*nothing*/ }
			public:
				///<summary>
				/// Always returns true.
				///</summary>
				virtual bool CanBeAssigned(System::String ^value) override
				{ return true; }
		};

		///<summary>
		/// Version for "Enum".
		///</summary>
		public ref class ParameterInfo_Enum :public ParameterInfo
		{
			private:
				array<System::String ^> ^_elements;
			internal:
				///<summary>
				/// Creates info for type "ParameterType::Enum".
				///</summary>
				ParameterInfo_Enum(System::String ^type);
			public:
				///<summary>
				/// Returns elements of enumeration.
				///</summary>
				property array<System::String ^> ^Elements
				{
					array<System::String ^> ^get()
					{ return _elements; }
				}
				virtual bool CanBeAssigned(System::String ^value) override;
		};

		///<summary>
		/// Version for "Int64" (with or without boundaries).
		///</summary>
		public ref class ParameterInfo_Int64 :public ParameterInfo
		{
			private:
				bool _hasBounds;
				ttg::math::int64 _lo;
				ttg::math::int64 _hi;
			internal:
				///<summary>
				/// Creates info for type "ParameterType::Int64".
				///</summary>
				ParameterInfo_Int64(System::String ^type);
			public:
				virtual bool CanBeAssigned(System::String ^value) override;
				///<summary>
				/// Returns true, if parameter type has bounds.
				///</summary>
				property bool HasBounds
				{
					bool get()
					{ return _hasBounds; }
				}
				///<summary>
				/// Returns low bound of type.
				///</summary>
				property ttg::math::int64 LowBound
				{
					ttg::math::int64 get()
					{ return _lo; }
				}
				///<summary>
				/// Returns high bound of type.
				///</summary>
				property ttg::math::int64 HighBound
				{
					ttg::math::int64 get()
					{ return _hi; }
				}
		};

		///<summary>
		/// Version for "Double" (with or without boundaries).
		///</summary>
		public ref class ParameterInfo_Double :public ParameterInfo
		{
			private:
				bool _hasBounds;
				double _lo;
				double _hi;
			internal:
				///<summary>
				/// Creates info for type "ParameterType::Double".
				///</summary>
				ParameterInfo_Double(System::String ^type);
			public:
				virtual bool CanBeAssigned(System::String ^value) override;
				///<summary>
				/// Returns true, if parameter type has bounds.
				///</summary>
				property bool HasBounds
				{
					bool get()
					{ return _hasBounds; }
				}
				///<summary>
				/// Returns low bound of type.
				///</summary>
				property double LowBound
				{
					double get()
					{ return _lo; }
				}
				///<summary>
				/// Returns high bound of type.
				///</summary>
				property double HighBound
				{
					double get()
					{ return _hi; }
				}
		};
	}
}
